home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / UTILITY / MIR105.ARJ / MIR_WP51.EXE / lha / HEAD.C < prev    next >
Text File  |  1992-05-11  |  11KB  |  346 lines

  1. /*
  2.  *  Usage - head  file_name [ line_count ] [/a][/t] > text
  3.  *
  4.  *  HEAD    Displays in printable format the first line_count lines
  5.  *          within a file; the default is 10 lines.  This clone of
  6.  *          the Unix HEAD and TAIL utilities provides a quick check on
  7.  *          the likely contents of a file.  If the "/a" option is used,
  8.  *          accented characters are treated as printable text.  If
  9.  *          "/t" is specified,, the display is of the TAIL of the
  10.  *          file, the LAST line_count lines.
  11.  *
  12.  *  input:  Normally an ASCII text file.
  13.  *
  14.  *  output: The specified number of lines is either displayed on the
  15.  *          screen or sent to a file.  Each non-printable character is
  16.  *          replaced by an ^ symbol.  If any line length exceeds 120
  17.  *          characters, a warning is issued.  If any line length exceeds
  18.  *          1024 or the file includes null bytes, the program advises
  19.  *          that the target file is not ASCII text.
  20.  *
  21.  *  writeup: MIR TUTORIAL ONE, topic 5
  22.  *
  23.  *  Written:    Douglas Lowry   Jan 10 92
  24.  *  Modified:   Douglas Lowry   Feb 29 92  Added /a, /t options.
  25.  *                              May 11 92  Correct re small files
  26.  *              Copyright (C) 1992 Marpex Inc.
  27.  *
  28.  *  For further information, contact
  29.  *              Innotech Inc., 110 Silver Star Blvd., # 107,
  30.  *              Scarborough, Ontario  Canada   M1V 5A2
  31.  *              Tel.  416 321-3838   FAX  416 321-0095
  32.  *
  33.  *  This program is free software; you may redistribute it and/or
  34.  *  modify it under the terms of the GNU General Public License as
  35.  *  published by the Free Software Foundation; either version 2 of
  36.  *  the License, or (at your option) any later version.
  37.  *
  38.  *  This program is distributed in the hope that it will be useful,
  39.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  40.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  41.  *  GNU General Public License for more details.
  42.  *
  43.  *  You should have received a copy of the GNU General Public
  44.  *  License (file 05LICENS) along with this program; if not,
  45.  *  write to the Free Software Foundation, Inc., 675 Mass Ave,
  46.  *  Cambridge, MA 02139, USA.
  47.  */
  48.  
  49. #include <stdio.h>
  50. #include <ctype.h>
  51. #include <io.h>
  52.  
  53. #define     MAX_BYTES   1024
  54.  
  55. #define     repeat      for(;;)
  56.  
  57. typedef     enum        _bool
  58.             { FALSE = 0, TRUE = 1 }  Bool;
  59. /*
  60.  *  declarations
  61.  */
  62.  
  63.     void    Usage_(), process();
  64.     Bool    locate() ;
  65.     char    *Cmdname_() {   return( "head" );    }
  66.  
  67. /*
  68.  *  MAIN
  69.  */
  70.  
  71. main( argc, argv )
  72.     int argc;
  73.     char    **argv;
  74. {
  75.     char    c10 ;       /*  argv[1][0]                        */
  76.     FILE    *fp ;
  77.     Bool    accent,     /*  user wants accented chars to show */
  78.             tail,       /*  show last lines, not first lines  */
  79.             tag ;       /*  argument is a tag (-.. or /..)    */
  80.     int     i ;
  81.     long int    line_ct ;
  82.  
  83.  /*  Usage - head  file_name [ line_count ] [/a][/t] > text  */
  84.  
  85.     c10 = argv[1][0] ;
  86.     if( argc < 2 || argc > 5 || c10 == '-' || c10 == '/' || c10 == '?' )
  87.         Usage_();
  88.  
  89.     if(( fp = fopen( argv[1], "rb" )) == NULL )
  90.     {
  91.         fprintf( stderr, "Can't open file %s\n", argv[1] ) ;
  92.         Usage_() ;
  93.     }
  94.  
  95.     line_ct = 10 ;
  96.     accent = tail = FALSE ;
  97.     for( i = 2 ; i < argc ; i++ )
  98.     {
  99.         tag = FALSE ;
  100.         if( argv[i][0] == '-' || argv[i][0] == '/' )
  101.             tag = TRUE ;
  102.         if( islower( argv[i][1] ))
  103.             argv[i][1] = toupper( argv[i][1] ) ;
  104.         if( tag && argv[i][1] == 'A' )
  105.             accent = TRUE ;
  106.         else if( tag && argv[i][1] == 'T' )
  107.             tail = TRUE ;
  108.         else
  109.         {
  110.             line_ct = atol( argv[i] );
  111.             if( line_ct < 1 )
  112.                 line_ct = 10 ;
  113.         }
  114.     }
  115.  
  116.     process( fp, line_ct, accent, tail );
  117.  
  118.     fclose( fp ) ;
  119.     exit( 0 );
  120. }
  121. /*
  122.  *  Usage
  123.  */
  124.     void
  125. Usage_()
  126. {
  127.     fprintf( stderr,
  128.     "usage:  %s  file_name [ line_count ] [/a][/t] > text\n\n\
  129.         Displays in printable format the first line_count lines\n\
  130.         within a file; the default is 10 lines.  This clone of\n\
  131.         the Unix HEAD and TAIL utilities provides a quick check on\n",
  132.             Cmdname_() );
  133.     fprintf( stderr,
  134. "        the likely contents of a file.  If the \"/a\" option is used,\n\
  135.         accented characters are treated as printable text.  If\n\
  136.         \"/t\" is specified,, the display is of the TAIL of the\n\
  137.         file, the LAST line_count lines.\n\n" ) ;
  138.     fprintf( stderr,
  139. "input:  Normally an ASCII text file.\n\n\
  140. output: The specified number of lines is either displayed on the\n\
  141.         screen or sent to a file.  Each non-printable character is\n\
  142.         replaced by an ^ symbol.  If any line length exceeds 120\n\
  143.         characters, a warning is issued.  If any line length exceeds\n" );
  144.     fprintf( stderr,
  145. "        1024 or the file includes null bytes, the program advises\n\
  146.         that the target file is not ASCII text.\n\n\
  147. writeup: MIR TUTORIAL ONE, topic 5\n\n" ) ;
  148.     exit( 1 ) ;
  149. }
  150.  
  151. #define     NON_PRINT       0
  152. #define     WHITE_SPACE     1
  153. #define     PUNCTUATION     2
  154. #define     DIGIT           3
  155. #define     CONSONANT       4
  156. #define     VOWEL           5
  157. #define     HI_CONSONANT    6
  158. #define     HI_VOWEL        7
  159. #define     TYPE_CT         8       /*  count of above types    */
  160.  
  161. /*
  162.  * PROCESS
  163.  */
  164.     void
  165. process( fp, line_ct, accent, tail )
  166.     FILE    *fp ;
  167.     long int     line_ct ;
  168.     Bool    accent,     /*  user wants accented chars to show */
  169.             tail ;      /*  show last lines, not first lines  */
  170. {
  171.    unsigned char   table[256] = {
  172.          0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* ctls */
  173.          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ctls */
  174. /*      bl  !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /     */
  175.          1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2,
  176. /*       0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?     */
  177.          3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
  178. /*       @  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O     */
  179.          4, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 4, 4, 5,
  180. /*       P  Q  R  S  T  U  V  W  X  Y  Z  [  \  ]  ^  _     */
  181.          4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 2, 2, 2, 2, 2,
  182. /*       `  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o     */
  183.          2, 5, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 4, 4, 5,
  184. /*       p  q  r  s  t  u  v  w  x  y  z  {  |  }  ~  NULL  */
  185.          4, 4, 4, 4, 4, 5, 4, 4, 4, 5, 4, 2, 2, 2, 2, 0,
  186. /*       Ç  ü  é  â  ä  à  å  ç  ê  ë  è  ï  î  ì  Ä  Å     */
  187.          6, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7,
  188. /*       É  æ  Æ  ô  ö  ò  û  ù  ÿ  Ö  Ü  ¢  £  ¥  ₧  ƒ     */
  189.          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0,
  190. /*       á  í  ó  ú  ñ  Ñ  ª  º  ¿  ⌐  ¬  ½  ¼  ¡  «  »     */
  191.          7, 7, 7, 7, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  192.          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  193.          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  194.          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  195.          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  196.          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  197.             };
  198.     unsigned char   line_in[ MAX_BYTES ] ;
  199.     Bool            printable,      /*  file is ASCII text      */
  200.                     at_eof ;        /*  at end of file          */
  201.     long int        over_120,       /*  To warn re line length  */
  202.                     line_no;
  203.     int             ch,             /*  one character           */
  204.                     len, i ;
  205.  
  206.     over_120 = 0 ;
  207.     printable = TRUE ;
  208.     at_eof = FALSE ;
  209.  
  210.     if( tail )
  211.     {
  212.         if( !locate( fp, line_ct ))
  213.             return ;
  214.     }
  215.  
  216.     for( line_no = 0 ; line_no < line_ct ; line_no++ )
  217.     {
  218.         for( len = 0 ; len < MAX_BYTES ; len++ )
  219.         {
  220.             if(( ch = fgetc( fp )) == EOF )
  221.             {
  222.                 if( feof( fp ))
  223.                 {
  224.                     at_eof = TRUE ;
  225.                     break ;
  226.                 }
  227.             }
  228.             if( isprint( ch ) || ch == '\t' )
  229.                 line_in[ len ] = ch ;
  230.             else if( !ch )
  231.             {
  232.                 printable = FALSE ;
  233.                 break ;
  234.             }
  235.             else if( ch == '\n' )
  236.                 break ;
  237.             else if( ch == '\015' || ch == '\032' )
  238.                 len-- ;     /*  delete carriage return, EOF     */
  239.             else if( !accent )
  240.                 line_in[ len ] = '^' ;
  241.             else if( table[ch] == NON_PRINT )
  242.                 line_in[ len ] = '^' ;
  243.             else
  244.                 line_in[ len ] = ch ;
  245.         }
  246.         line_in[ len ] = '\0' ;
  247.  
  248.         if( len > MAX_BYTES - 2 || !printable )
  249.         {
  250.             fprintf( stderr,
  251. "\nNot printable ASCII.  Use f_print filter for display.\n" ) ;
  252.             fclose( fp ) ;
  253.             Usage_();
  254.         }
  255.         if( len > 120 )
  256.             over_120++ ;
  257.  
  258.         if( puts( line_in ))
  259.         {
  260.             fprintf( stderr, "Unable to write... FATAL.\n\n" ) ;
  261.             exit( 1 ) ;
  262.         }
  263.  
  264.         if( at_eof )
  265.             break ;
  266.     }
  267.  
  268.     if( over_120 )
  269.         fprintf( stderr, "\n*** %d LINES OVER 120 BYTES LONG ***\n\n",
  270.                 over_120 ) ;
  271.     return ;
  272. }
  273. /*
  274.  *  LOCATE - Find beginning point for the last line_ct lines
  275.  */
  276.     Bool
  277. locate( fp, line_ct )
  278.     FILE    *fp ;
  279.     long int     line_ct ;
  280. {
  281.     unsigned char   buf[ MAX_BYTES ] ;
  282.     Bool        gotcha ;    /*  found desired offset    */
  283.     long int    line_no,
  284.                 buf_len,
  285.                 fil_len,
  286.                 bgn_at ;    /*  offset of buffer start */
  287.     int         i ;
  288.  
  289.     fil_len = filelength( fileno( fp )) ;
  290.     if( fil_len < 1 )
  291.         return( FALSE ) ;
  292.     bgn_at = fil_len ;
  293.     line_no = 0 ;
  294.     gotcha = FALSE ;
  295.  
  296.     while( !gotcha )
  297.     {
  298.         bgn_at -= MAX_BYTES ;
  299.         if( bgn_at < 0 )
  300.             bgn_at = 0 ;
  301.         if( fseek( fp, bgn_at, SEEK_SET ))
  302.         {
  303.             fprintf( stderr, "Unable to position file.  FATAL!\n\n" );
  304.             return( FALSE ) ;
  305.         }
  306.         buf_len = fread( buf, sizeof( char ), MAX_BYTES, fp ) ;
  307.         if( fil_len >= MAX_BYTES && buf_len < MAX_BYTES )
  308.         {
  309.             fprintf( stderr, "Trouble reading back in file.  FATAL!\n\n" );
  310.             return( FALSE ) ;
  311.         }
  312.  
  313.         for( i = buf_len - 1 ; i > -1 ; i-- )
  314.         {
  315.             if( buf[i] == '\n' )
  316.             {
  317.                 if( ++line_no > line_ct )
  318.                 {
  319.                     bgn_at += ( i + 1 ) ;
  320.                     gotcha = TRUE ;
  321.                     break ;
  322.                 }
  323.             }
  324.             if( !buf[i] )    /*  null byte   */
  325.             {
  326.                 fprintf( stderr,
  327. "\nNot printable ASCII.  Use f_print filter for display.\n" ) ;
  328.                 fclose( fp ) ;
  329.                 Usage_();
  330.             }
  331.             if( !bgn_at )
  332.             {
  333.                 gotcha = TRUE ;
  334.                 break ;     /*  Must start at beginning     */
  335.             }
  336.         }
  337.     }
  338.  
  339.     if( fseek( fp, bgn_at, SEEK_SET ))
  340.     {
  341.         fprintf( stderr, "Unable to position file.  FATAL!\n\n" );
  342.         return( FALSE ) ;
  343.     }
  344.  
  345.     return( TRUE ) ;
  346. }